package com.laviedesfons.jhmtasc.types.abstracts;

import com.laviedesfons.jhmtasc.exceptions.MException;
import com.laviedesfons.jhmtasc.metadata.MetaField;
import com.laviedesfons.jhmtasc.metadata.MetaModel;
import com.laviedesfons.jhmtasc.metadata.TypeUtils;
import com.laviedesfons.jhmtasc.types.interfaces.InternalType;
import fr.x9c.cadmium.kernel.Value;

/**
 *
 * @author Romano
 */
public abstract class AbstractType<T> implements InternalType {

    private MetaModel model = null;
    protected String flag = "";
    protected T wrapped = null;

    public T getWrapped() {
        return wrapped;
    }

    @Override
    public abstract InternalType fromValue(Value v) throws MException;

    @Override
    public abstract Value toValue();

    final MetaField getField(Value v) throws MException{
        if (v.isLong()) {
            return getMetaModel().getOffsetField(v.asLong());
        } else if (v.isBlock()) {
            return getMetaModel().getValueField(v.asBlock().getTag());
        }
        throw new MException("unable to read flag id");
    }

    public void setMetaModel(MetaModel model) {
        this.model = model;
    }

    protected final MetaModel getMetaModel(){
        if(model == null){
            model = TypeUtils.getTypeUtils().getMetaModel(this.getClass());
        }
        return model;
    }

    int getParentId(){
        if(getMetaModel().getParentField() != null){
            return getMetaModel().getParentField().getId();
        }
        return -1;
    }

    public String getFlag(){
        return flag;
    }

    @Override
    public String toString() {
        return this.getClass().getSimpleName()+"{" + "flag=" + flag + ", wrappedObject=" + wrapped + '}';
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final AbstractType<T> other = (AbstractType<T>) obj;
        return true;
    }

    @Override
    public int hashCode() {
        int hash = 5;
        hash = 97 * hash + (this.model != null ? this.model.hashCode() : 0);
        hash = 97 * hash + (this.flag != null ? this.flag.hashCode() : 0);
        hash = 97 * hash + (this.wrapped != null ? this.wrapped.hashCode() : 0);
        return hash;
    }
}